The documentation for making lists is separate from the main documentation for the sake of clarity, and because list use is optional. Lists are the most powerful and most complicated feature of ACE. If you want to use lists in your module, you should design and test the module without lists first.
Introduction
A list is a series of items arranged one on-top of the other. The list appears in a rectangular box, with a vertical scroll bar on the right hand side:
The ACE! list system is designed to handle save game data that is naturally displayed as a list. In most games, this is an inventory (the items carried by a character). However the list system can be used to display any other type of information (spell lists, conditions etc).
Manipulating lists
Assuming you are using a module that makes use of lists, and that you have opened a save game, select a list by clicking on it or by pressing the tab key. A focus ring will be drawn around the list. Select an item in the list by clicking on it (you can select only one item at a time). From the Edit menu, choose Add Item…, Edit Item… or Remove Item. The first two options produce the item editing dialog (I.E.D), which allows you to set various characteristics of the item.
You can edit an item by pressing the enter or return key, or by double clicking it (the latter will not work with appearance manager 1.0.0, supplied with MacOS 8.0). You can delete an item by pressing the delete key.
There are many keyboard shortcuts you can use to edit a list. Refer to the "Hints" section of the "Read Me" document for a description.
Data Groups
Central to the inventory system is the idea of 'data groups'. A data group is a set of offsets that determine one aspect of an inventory item (the user 'sees' data groups as controls in the item editing window). The simplest inventory system has only one data group - an id which specifies the item.
Example: In 'Might & Magic' the six items in a character's backpack are specified by six byte values in sequence.
A slightly more complicated inventory system might use two data groups, one for the id that specifies the item, and one to indicate how the item is used.
Example: Bard's Tale uses two data groups, the first indicates if the item is equipped, the second identifies the item.
A data group visibly corresponds to a control in the item editing dialog (see the picture above, which illustrates the item editing dialog for Bard's Tale). The ACE list system allows for a maximum of eight data groups.
List Implementation
The first step in making a list is simply to display it. The minimum steps required to display a list are:
• Modify the 'DITL' resources (you must have separate appearance manager and non-appearance manager dialogs for any dialog that contains a list),
• Add a 'ACEl' resource,
• Add/Modify any 'STR#' resources referred to by the 'ACEl' resource,
• Add/Modify the 'ACEi' resource(s),
and, if ACE is running on an appearance manager system
• Add a 'CNTL' resource,
• Add a 'ldes' resource
To make a list editable, you must
• Add one or two item editing dialogs ('DITL' resources),
• Add any 'CNTL' and 'ldes' resources required for the above dialogs,
• Add two 'DLOG' resources and one 'dlgx' resource required for the above dialogs,
List Procedures
The exact procedures used to display, edit, add and remove items are as follows:
The displayed string for each item in the list is generated as follows: For each data group, if it is to be displayed, the group value for the item is obtained, parsed via the list "equation to screen" (if specified) and then used to get the display string (the value is the 'STR#' resource index). This string is added to the end of the item string.
When an item is edited, the group values for the selected item are determined. The item editing dialog is displayed, with each of the controls in the dialog set according to the group value, which are first parsed via the "equation to IED" (if specified). If the user clicks the cancel button, then the dialog is dismissed and nothing more is done. If the user clicks the OK button, the value of each control is read and parsed by the "equation from IED" (if specified). The list is sorted, if required, and then redrawn.
When a new item is added, the item editing dialog is displayed. Each of the controls is set according to the group delete value, which is parsed via the "equation to IED" (if specified). If the user clicks the cancel button, the dialog is dismissed and nothing more is done. If the user clicks the OK button, the value of each control is read and parsed by the "equation from IED" (if specified). The list is sorted, if required, and then redrawn. If required, the total number of items parsed through an equation (if specified) and then recorded.
When an item is removed, the delete value for each group is written over the selected item, and the item is visibly removed from the list. The list is shuffled, if this is required. The total is also adjusted, as appropriate, as per a new item.
List Resources
The following resources are new or changed (You will need to install templates to edit them, See Appendix B for more information). Unless specified, any resource id (>128) and any (or no) resource name can be used.
'ACEl' - the ACE list resource
There is one 'ACEl' resource for each list. The resource id of the first 'ACEl' resource should be 128 (with subsequent resource +1). The name of the 'ACEl' resource should be the name of the list items as used in the game, in a singular form. For example, if the list is a list of spells, the name of the 'ACEl' resource should be "Spell". This is used to set the title of the item editing dialog.
The fields of the 'ACEl' resource are:
• Width - the width in pixels of the list as it appears in an appearance manager tabbed window. This can be read from the width field of the 'CNTL' resource. This is necessary to work around a bug in the Macintosh Toolbox. If your module does not have tabbed windows, you can leave this field as 0.
• Height - the height in pixels of the list. See above.
• Primary group - the group whose data is used for sorting and/or shuffling. Additionally, the delete value of the primary group is used to determine where the list ends, and whether an item exists or not.
• Sort - whether the inventory list should be sorted.
• Shuffle - whether the inventory list have 'blank' entries removed.
• Sort direction [byte] - The direction of the sort: 0 - ascending or 1 - descending (see the section 'Sort').
• Shuffle direction [byte] - shuffle items to the top (0) or bottom (1) of the list (see the section 'Shuffle').
• Maximum [short] - the maximum number of items in the list. The user will not be permitted to add more than this number of items to the inventory.
• Total [boolean] - whether the total number of items should be recorded.
• Offset [long] - the location to write the total to.
• Equation [boolean] - whether the total should be parsed by the equation in STR#132, index 1.
At least one, and no more than eight data group descriptions. The order of the groups determines the order in which strings are added to make up the item name.
• Minimum - the minimum value, as used in the item editing dialog. Because equations are often applied to the group values in the item editing dialog, this may be different from the minimum value that can appear in the save file.
• Maximum - the maximum value. The same conditions as for the 'Minimum' field (above) apply.
• Offset - the offset of the first occurrence of the data group. You can have two or more groups using the same offset if necessary (e.g. to read the high and low nibbles of a byte).
• Delete - the value this data group takes when an item is deleted from the list.
• Next - the addend that determines the next item in the data group (can be positive or negative). If the data type (see Type field below) is a byte, short or long, then this is a number of bytes. Otherwise, it has the same 'units' as the data type (e.g. if the data type is a bit, then this is a number of bits).
• Display id - determines how (or if) the group is displayed. To display the group value directly, the Display id is -1. To not display a group at all, the Display id is 0. To use the strings in a STR# resource for display, the Display id should be the id of the STR# resource (id ≥150). Finally, to use an equation to determine which STR# resource to use for display, the Display id is the index of the string in the STR#140 resource which contains the equation. The last option is used when linking a pop-up menu to a list (see the section on Control Linking in "Development (part III)").
• Equation to screen - the equation used to parse the value before the initial display in the main window (0 - no equation, otherwise the index of a STR#133 resource). Note that this equation does not actually alter the data value.
• Equation to IED - the equation used to parse the group value before using it to set the control in the item editing dialog (0 - no equation, otherwise the index of a STR#134 resource).
• Equation from IED - the equation used to parse the control value in the item editing dialog before writing it back to the main window (0 - no equation, otherwise the index of a STR#135 resource).
• Write? - whether the group should actually be written back to the file.
• Value Equation - If the group is written (see "Write?" above), and the index of the display string is determined by offset (see "Index by" below), then the value that is actually written must be determined by this equation. This is the index of a STR#136 resource.
• Type - the data type (short, long etc).
• Pad Id - the index of the STR#137 resource added to the end of each item string or 0 for no equation.
• Index by - indicates how the offset for the display string is determined (1 - the value determines the index of the string, 2 - the offset determines the string index).
'ACEi' - the ACE dialog item mapping resource
The 'ACEi' resource continues to operate as documented, with the following modifications:
1. If you use any lists in your dialog, you must have an 'ACEi' resource (even with a non-appearance manager, non-tabbed dialog).
2. All dialog item id's for lists are placed at the end of the 'ACEi' resource. So, for example, if a module uses 3 lists, the last three entries in each 'ACEi' resource are the dialog item id's of the lists.
'DITL' - The dialog item list
A list in a non-appearance manager dialog is implemented as a user item. A list in an appearance manager dialog is implemented as a control. In both cases, the dialog item must be enabled.
For tabbed dialogs, it is often convenient to put a list in a separate dialog pane. Refer to "Development (Tabs)" for more information.
You will need one or two additional dialogs for each list - the item editing dialog(s). The dialog should contain two buttons ('OK' id 1 and 'Cancel' id 2) and one control (edit text item, checkbox, pop-up menu or list) for each data group (id 3+). The dialog may also contain static items.
The non-appearance manager and appearance manager item editing dialogs are arranged in pairs just like other 'DITL' resources. The first item editing dialog has an id of 400. If the item editing dialog contains no appearance manager specific controls, you do not need to provide a separate appearance manager dialog.
In the item editing dialog, Edit text items may only have numbers entered into them.
'CNTL' - The control template
Appearance manager lists are implemented as dialog controls, which in turn require a 'CNTL' resource. Refer to Appendix G for information on how to set each field of the 'CNTL' resource.
The 'CNTL' resources are numbered using the following convention: List controls in non-tabbed dialogs start at id 4000, list controls in tabbed dialogs start at id 4100, list controls in item editing dialogs start at 4200.
'dlgx' - Extended dialog template
You should have one 'dlgx' resource for each item editing dialog. The resource id will therefore be 401, 403, 405… etc (unless the appearance and non-appearance dialogs are the same). Copy the 'dlgx' resource from the "Module template" document.
'ldes' - the list description resource
This resource is needed for appearance manager lists. You should modify the following fields:
• Number of rows - the number of rows in the list.
• Number of columns - always set this to 1.
• Has vertical scroll bar: 1
All other fields should be left at their default value (note that it is not necessary to specify the cell height or cell width as a value of 0 ensures that it is calculated automatically).
You can give the resource any id number, but the convention is to use the same id as the corresponding 'CNTL' resource (remember that the 'CNTL' resource specifies the 'ldes' resource in its 'Value' field). It is not necessary to have one unique 'ldes' resource for each appearance manager list control - two or more 'CNTL' resources can refer to the same 'ldes' resource.
List Equations
The list system make extensive use of equations. These equations use the syntax described in the "Equation Parser" section of "Development (part III)". When a data group is to be displayed in the item editing window as a list, the most common equation used for the "equation to IED" is x-1, because the first item in a list is selected with a value of zero. This is then matched with an "equation from IED" of x+1. There are two special cases of equations used with lists:
1. The equations used to parse the values read from the controls in the item editing dialog (the "equations from IED") have one additional feature: They can refer to the value of other controls in the item editing dialog. The control values are stored in an array, y[0] is the first group, y[1] is the second group etc.
This allows you to have two (or more) controls in the item editing dialog, whose values are then combined, and only the resulting value is actually written back to the file.
Example: In Realmz, the list of conditions is implemented as two groups. The first group is used to obtain the duration of the condition - temporary ($A) or permanent ($FFFF). The second group determines the actual condition. The "equation from IED" for the second group is 10 + 65525 * (y[0] - 1), where y[0] is the value of the first group. Only the second group is written to the file.
2. The equations that can be used to link a pop-up menu to a list can refer to the value of other controls in the dialog. The control values are stored in an array, c[0] is the first control number, c[1] is the second etc.
Example: The Might & Magic II module links the 'Class' pop-up menu to the spell list so that if the selected class is Paladin or Cleric, the list of Cleric spells is displayed instead of the list of Sorcerer spells. Sorcerer spells are stored in the STR#152 resource, and Cleric spells are in the STR#153 resource. The control number for the class pop-up is 24, and the values that the pop-up menu takes for Paladin and Cleric are 2 and 4 respectively. The equation used to link the pop-up menu value to a STR# resource is 152+(c[23]=2)+(c[23]=4).
List Sort
A sort orders the items (i.e. all the group values) into order. This order is based on the primary group, and can be either ascending (lower values at the top) or descending (higher values at the top). Note that the top of this list is the position of the first item (determined by the primary group offset).
Note: Equipment lists in RPG games are sometimes sorted on the item type, or on their readied/unreadied status. You can test to see if a list is sorted by inspecting the location in the save file that contains the list with a data or resource fork editor, then using the game to add an item, the inspecting the save file again.
If the "Sort" field of the list's 'ACEl' resource is true, the list will be sorted whenever the user adds or edits an item. The list will not be sorted before being initially displayed (it is assumed that the game in question keeps the list sorted).
You should never sort a list if any group uses the offset index to determine the string index (the "Index by" field), and in fact, it makes no sense to do so anyway.
List Shuffle
A shuffle gathers the "non-existant" items and move them all to the top or bottom of the list. An item is non-existant if it's primary group value is equal to the delete value. Note that the top of this list is the position of the first item (determined by the primary group offset) and the bottom of the list is determined by the number of items, the "next" field and the position of the first item.
Note: Equipment lists, such as those used in RPG's, are often shuffled. You can test to see if a list is shuffled by inspecting the location in the save file that contains the list with a data or resource fork editor, then using the game to remove an item, the inspecting the save file again.
If the "Shuffle" field of the list's 'ACEl' resource is true, the list will be shuffled every time the user removes an item. The list will not be shuffled before being initially displayed (it is assumed that the game in question keeps the list shuffled).
You should never shuffle a list if any group uses the offset index to determine the string index (the "Index by" field), and in fact, it makes no sense to do so anyway.
Height and Width of Lists
A single list item (or cell) is 16 pixels high. For a list to display, say n items, one would therefore expect the list to be (n x 16) pixels high. However, the height of a list includes the border, which is a different size on appearance manager lists (controls) and non-appearance manager lists (user items). The exact formulae are:
Appearance manager lists:
list height = (n x 16) + 6
Non-appearance manager lists:
list height = (n x 16) + 2
The list width includes the vertical scroll bar.
Remember that appearance manager lists that appear in tabbed windows have their width and height specified in the 'ACEl' resource (see the section on the 'ACEl' resource).
Changing the order of groups
You may find that you want to change the order of the groups in a 'ACEl' resource. To do this:
1. Change the groups in the 'ACEl' resource.
Hint: You can Cut, Copy and Paste an entire group in ResEdit.
2. If necessary, change the primary group field of the 'ACEl' resource.
3. Renumber the dialog items in the two item editing dialogs.
4. Change the index of any 'Equations from List' or 'Value Equations' that refer to other groups in the item editing dialog.
Examples
The following examples of lists are intended to help you understand the ACE list system. Some examples list the equations used on each group. For clarity, these equations are written with x= preceding them. Note however that, as with all ACE equations, the x= is not entered in the actual STR# resources.
This section does not detail all the lists used in all modules.
Might & Magic (1):
1. Backpack items
$50 - filler byte (always 0)
$51 - first item (1-255 or 0 for no item)
etc
One group, shuffled (top), not sorted, no total, maximum 6 items.
Group 1: min 0, max 255, offset $51, next +2, delete 0, type byte, index by value.
Note: We use the equation x=x-1 before displaying group 1 in the item editing dialog, since the first (valid) item takes a value of 1, but the first item in the list is selected with x=0. Likewise, when exiting the item editing dialog, we use the equation x=x+1.
Bard's Tale:
1. Equipment
$24 - equipped status (0 unequipped, $80 equipped) for first item
$25 - first item (1-127 or 0 for no item)
etc
Two groups, primary group 2, shuffled (top), not sorted, no total, maximum 8 items.
Group 1: min 0, max 1, offset $24, next +2, delete 0, type byte, index by value.
Group 2: min 0, max 127, offset $25, next +2, delete 0, type byte, index by value.
Note: We use the equation x=x/128 before displaying group 1 in the item editing dialog. This maps the equipped value ($80 = 128) to 1 and the unequipped value stays at 0. Likewise, when exiting the item editing dialog, we use the equation x=x*128. Group 2 uses the same equations as used in the Might & Magic (1) example above, for the same reasons.
Might & Magic II:
1. Backpack items
$3F - $44 - item (1-6) type (1-255 or 0 for no item)
$45 - $4A - item (1-6) charges (1-255 or 0 for item w/o charges)
$4B - $50 (top 2 bits) - item (1-6) alignment (1-3 for evil, good, neutral, or 0 for any)
$4B - $50 (bottom 5 bits) - item (1-6) enchantment (1-31 or 0 for no enchantment)
Four groups, primary group 1, shuffled (top), not sorted, no total, maximum 6 items.
Group 1 (type): min 0, max 255, offset $3F, next +1, delete 0, type byte, index by value.
Group 2 (enchantment): min 0, max 31, offset $4B, next +1, delete 0, type byte, index by value.
Group 3 (charges): min 0, max 255, offset $45, next +1, delete 0, type byte, index by value.
Group 4 (alignment): min 0, max 3, offset $4B, next +1, delete 0, type byte, index by value.
Note: The ordering of groups determines the order in which they are displayed for each item. In this case, the order produces "Type +enchantment (charges) (alignment)".
Note: Group 2 and group 4 both read from the same offsets, but only group 4 is written back to that offset. The "equation from IED" for group 4 combines the two groups with the equation x=(y[1] mod 32)+((y[3]-1)*64), where y[1] is group 2 and y[3] is group 4.
2. Spells
$56 - $5B (bit) - spells (1 for learnt, 0 for not learnt)
One group, not shuffled, not sorted, no total, maximum 48 items.
Group 1: min 0, max 1, offset $56, next + 1, delete 0, type bit0, index by offset.
Note: The spell list uses "index by offset" to determine what spells have been learnt.
Note: Rather than specifying a type of just bit, bit0 is specified. This is the specific bit of offset $56 that the spell list starts on. If the spell list started on bit 4 of offset $56, the type would be bit4. A similar situation applies to the two 'nibble' (half-byte) data types.
Might & Magic III:
1. Inventory
$7D - $8E - item (1-18) ready (1-13 or 0 for unreadied)
$90 - $A1 - item (1-18) charges (1-255 or 0 for no charges)
$A3 - $B4 - item (1-18) element (1-36 or 0 for no element)
$B6 - $C7 - item (1-18) material (1-22 or 0 for no material)
$C9 - $DA - item (1-18) ability (1-72 or 0 for no ability)
$DC - $ED - item (1-18) type (1-103 or 0 for no item)
$EF - $100 - item (1-18) power (1-78 or 0 for no power)
Seven groups, primary group 5, shuffled (top), not sorted, no total, maximum 18 items.
Group 1 (ready): min 0, max 13, offset $7D, next + 1, delete 0, type byte, index by value.
Group 2 (element): min 0, max 36, offset $A3, next + 1, delete 0, type byte, index by value.
Group 3 (material): min 0, max 22, offset $B6, next + 1, delete 0, type byte, index by value.
Group 4 (ability): min 0, max 255, offset $C9, next + 1, delete 0, type byte, index by value.
Group 5 (type): min 0, max 255, offset $DC, next + 1, delete 0, type byte, index by value.
Group 6 (power): min 0, max 255, offset $EF, next + 1, delete 0, type byte, index by value.
Group 7 (charges): min 0, max 255, offset $90, next + 1, delete 0, type byte, index by value.
Note: As you can probably guess, the ACE list system was designed to accommodate this particular case.
2. Spell list
$53 - $76 - Spells (0 not learnt, 1 learnt)
One group, not shuffled, not sorted, no total, maximum 35 items.
Group 1: min 0, max 1, offset $53, next + 1, delete 0, type byte, index by offset.
Realmz:
1. Inventory
$124 - $125 - item 1 type
$126 - item 1 readied (0 not readied, 1 readied)
$127 - item 1 identified (0 not identified, 1 identified)
Four groups, primary group 1, shuffled (top), not sorted, total at offset $17, maximum 30 items.
Group 1 (type): min 0, max 180, offset $124, next +6, delete 0, type unsigned short, index by value.
Group 2 (readied): min 0, max 1, offset $126, next +6, delete 0, type byte, index by value.
Group 3 (identified): min 0, max 1, offset $127, next +6, delete 0, type byte, index by value.
Group 4 (charges): min 0, max 65535, offset $128, next +6, delete 0, type unsigned short, index by value.
Note: In the item editing dialog, an infinite number of charges is displayed as -1 rather than 65535. Ideally, this group would be displayed as two radio buttons, one of which is labeled "Infinite", the other leading to an edit text field that allows the number of charges to be entered. However, ACE cannot (yet) use radio buttons in the item editing dialog.
Two groups, primary group 2, not shuffled, not sorted, no total, maximum 40 items.
Group 1: min 0, max $FFFF, offset $62, next +2, delete 0, type unsigned short, index by value.
Group 2: min 0, max $FFFF, offset $62, next +2, delete 0, type unsigned short, index by offset.
Note: Group 1 (index by value) determines the duration of the condition, group 2 (index by offset) determines the actual condition. Only the second group is actually written back to the file.